package za.org.jcicada.genss.lifecycle.impl;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import za.org.jcicada.genss.SystemURN;
import za.org.jcicada.genss.lifecycle.ILifeCycleClient;
import za.org.jcicada.genss.lifecycle.ILifeCycleServer;
import za.org.jcicada.genss.lifecycle.LogLevel;
import za.org.jcicada.genss.messages.Result;
import za.org.jcicada.genss.messages.SuccessCode;

public class LifeCycleServer implements ILifeCycleServer {

    /**
     * Logger object used for logging messages.
     */
    private static final Log logger = LogFactory.getLog(LifeCycleServer.class);

    /** Map of systems and their callback interfaces. */
    private Map<SystemURN, ILifeCycleServer.ICallback> systemMap = new HashMap<SystemURN, ILifeCycleServer.ICallback>();

    /**
     * Add a new system by specifying the systemURN and callback handler
     * 
     * @param systemURN the system URN
     * @param callback the callback handler
     */
    public void addSystem(SystemURN systemURN, ILifeCycleServer.ICallback callback) {
        if (systemURN == null || callback == null) {
        	String message = String.format("Received null argument: systemURN=%s, callback=%s", systemURN, callback);
            logger.error(message);
            throw new IllegalArgumentException(message);
        }
        systemMap.put(systemURN, callback);
    }
    
    /**
     * Stop the lifecycle server. Currently does nothing because this class
     * is stateless.
     */
    public void stop() {
    }

    public void informDisconnect(ILifeCycleClient observer) {
        // do nothing because no references held to clients
    }

    public void requestHalt(ILifeCycleClient observer, SystemURN systemURN) {
        logger.info(String.format("%s received HALT request for %s", getClass(), systemURN));
    	if (!systemMap.containsKey(systemURN)) {
    		observer.replyHalt(new Result(SuccessCode.COMPLETE_FAILURE, "Unrecognized systemURN=" + systemURN), systemURN);
    	}
    	else {
    		observer.replyHalt(systemMap.get(systemURN).shutdown(ILifeCycleServer.Shutdown.HALT), systemURN);
    	}
    }

    public void requestRestart(ILifeCycleClient observer, SystemURN systemURN) {
        logger.info(String.format("%s received RESTART request for %s", getClass(), systemURN.toString()));
    	if (!systemMap.containsKey(systemURN)) {
    		observer.replyRestart(new Result(SuccessCode.COMPLETE_FAILURE, "Unrecognized systemURN=" + systemURN.toString()), systemURN);
    	}
    	else {
    		observer.replyRestart(systemMap.get(systemURN).shutdown(ILifeCycleServer.Shutdown.RESTART), systemURN);
    	}
    }

    public void requestSetLogLevel(ILifeCycleClient observer, SystemURN systemURN, LogLevel level) {
        logger.info(String.format("%s received LOGLEVEL request for %s", getClass(), systemURN.toString()));
    	if (!systemMap.containsKey(systemURN)) {
    		observer.replySetLogLevel(new Result(SuccessCode.COMPLETE_FAILURE, "Unrecognized systemURN=" + systemURN.toString()), systemURN, level);
    	}
    	else {
    		observer.replySetLogLevel(systemMap.get(systemURN).setLogLevel(level), systemURN, level);
    	}
    }
    
    public void requestReconnect(ILifeCycleClient observer, SystemURN systemURN) {
        logger.info(String.format("%s received RECONNECT request for %s", getClass(), systemURN.toString()));
    	if (!systemMap.containsKey(systemURN)) {
    		observer.replyReconnect(new Result(SuccessCode.COMPLETE_FAILURE, "Unrecognized systemURN=" + systemURN.toString()), systemURN);
    	}
    	else {
    		observer.replyReconnect(systemMap.get(systemURN).reconnect(), systemURN);
    	}
    }
    
    public void requestPing(ILifeCycleClient observer, SystemURN systemURN) {
    	logger.info(String.format("%s received PING request for %s", getClass(), systemURN.toString()));
    	if (!systemMap.containsKey(systemURN)) {
    		observer.replyPing(new Result(SuccessCode.COMPLETE_FAILURE, "Unrecognized systemURN=" + systemURN.toString()), systemURN);
    	}
    	else {
    		observer.replyPing(systemMap.get(systemURN).ping(), systemURN);
    	}
    }

}
